#-*-coding:utf-8-*-
import csv_io
import optparse
import os

def parse_log_line(line):
    items = line.strip().split(' ')
    entry = []
    if items[0] == 'Warning:' and items[4] == 'collision':
        entry.append("collision") # type
        entry.append(items[3].strip("';")) # user
        entry.append(items[6].strip("',")) # user
    elif items[0] == "Warning:" and items[1] == 'Vehicle' and items[3] == 'performs' and items[15] == 'red':
        entry.append(float(items[18].split('=')[-1].strip('),'))) # deceleration
        entry.append(items[2].strip("'")) # user
    return entry

def aggregate_violation(entry_sets, DEC_BOUND=-4.0):

    user_entry = {}

    for i in range(len(entry_sets)):
        assert type(entry_sets[i]) is list
        for item in entry_sets[i]:
            assert type(item) is list
            if len(item) == 0:
                continue
            user_1 = item[1]
            user_2 = item[-1]
            user_entry.setdefault(user_1, {"collision":0, "red":0})
            user_entry.setdefault(user_2, {"collision":0, "red":0})
            if item[0] == 'collision':
                user_entry[user_1]["collision"] += 1
                user_entry[user_2]["collision"] += 1
            elif item[0] < DEC_BOUND:
                user_entry[user_1]["red"] += 1
    return user_entry

def process_logset(log_set, DEC_BOUND=-4.0):
    entry_sets = [csv_io.read_log(logs, parse_log_line) for logs in log_set]
    assert type(entry_sets) is list
    user_entry = aggregate_violation(entry_sets=entry_sets, DEC_BOUND=DEC_BOUND)
    return user_entry

def parse_habit(line):
    entry = [line[0]]
    entry.extend(map(float, line[1:]))
    return entry

def aggregate_habit(habit_set):

    user_habit_tmp = {}
    assert type(habit_set) is list
    for i in range(len(habit_set)):
        assert type(habit_set[i]) is list
        for item in habit_set[i]:
            user = item[0]
            user_habit_tmp.setdefault(user, [])
            user_habit_tmp[user].append(item[1:])

    user_habit = {}

    for user in user_habit_tmp:
        items  = user_habit_tmp[user]
        habit = [0] * 9
        for item in items:
            habit[0] += item[0] # driving time
            habit[1] += item[1] # driving distance
            habit[2] = max(habit[2], item[2]) # max speed
            habit[3] += item[3] # average speed
            habit[4] = max(habit[4], item[4]) # max deceleration
            habit[5] = max(habit[5], item[5]) # max acceleration
            habit[6] += item[6] # average deceleration
            habit[7] += item[7] # average acceleration
            habit[8] += item[8] # intersection

        habit[0] /= len(items)
        habit[1] /= len(items)
        habit[3] /= len(items)
        habit[6] /= len(items)
        habit[7] /= len(items)
        habit[8] /= len(items)

        user_habit.setdefault(user, habit)

    return user_habit

def process_habit_set(file_set):
    habit_set = [csv_io.read_csv(fname, parse_habit, delimiter=',', header=True) for fname in file_set]
    assert type(habit_set) is list
    user_habit = aggregate_habit(habit_set)
    return user_habit

def parse_events(line):
    entry = [line[0]]
    entry.extend(map(float, line[2:]))
    if len(entry) == 2:
        entry.append(0)
    return entry

def aggregate_events(event_set):
    user_feat = {}
    assert type(event_set) is list
    for i in range(len(event_set)):
        assert type(event_set[i]) is list
        for item in event_set[i]:
            user = item[0]
            user_feat.setdefault(user, [0] * 3)
            user_feat[user][0] += 1
            user_feat[user][1] += item[1]
            user_feat[user][2] += item[2]
    return user_feat

def process_events(file_set):
    assert type(file_set) is dict
    event_user = {}
    for event in file_set:
        event_set = [csv_io.read_csv(fname, parse_events, delimiter=',', header=True) for fname in file_set[event]]
        event_user.setdefault(event, aggregate_events(event_set))

    # convert to user event format
    user_event = {}
    for event in event_user:
        for user in event_user[event]:
            user_event.setdefault(user, {})
            user_event[user].setdefault(event, event_user[event][user])

    return user_event

def generate_mapping(users):
    user_id = {}
    id = 0
    for user in users:
        user_id.setdefault(user, id)
        id += 1
    return user_id

def get_options(args=None):
    parser = optparse.OptionParser()
    parser.add_option("--inputdir", dest="input", help="input directory")
    parser.add_option("--outdir", dest="output", help="output directory")
    parser.add_option("--bound", dest="bound", type="float", help="deceleration bound")
    (options, args) = parser.parse_args(args=args)

    if not options.input or not options.output:
        parser.print_help()
        exit(0)
    if not options.bound:
        options.bound = -2.0
    return options

def process(options=None):
    # scan inputdir:
    log_set = []
    habit_set = []
    events_set = {}
    history_set = []
    for name in os.listdir(options.input):
        fname = os.path.join(options.input, name)
        if os.path.isfile(fname):
            key = None
            if name.find("abruptTurn.feat")!=-1:
                key = "at"
            elif name.find("acc.feat")!=-1:
                key = "acc"
            elif name.find("dec.feat")!=-1:
                key = "dec"
            elif name.find("os.feat")!=-1:
                key = "os"
            elif name.find("habit")!=-1:
                key = "habit"
            elif name.find("logs")!=-1:
                key = "logs"
            elif name.find("history")!=-1:
                key = "history"

            if key == "at" or key == "acc" or key == 'dec' or key == 'os':
                events_set.setdefault(key, [])
                events_set[key].append(fname)
            elif key == 'logs':
                log_set.append(fname)
            elif key == "habit":
                habit_set.append(fname)
            elif key == "history":
                history_set.append(fname)
    #
    user_history = process_logset(history_set, DEC_BOUND=options.bound)
    # process log set
    user_entry = process_logset(log_set, DEC_BOUND=options.bound)
    # process habit set
    user_habit = process_habit_set(habit_set)
    # process events set
    user_event = process_events(events_set)

    mapping = generate_mapping(user_habit)
    # write mapping
    csv_io.write_csv(os.path.join(options.output, "mapping.csv"), mapping.items(), header="origin,id")

    # fuse
    user_feature = []
    for user in user_habit:
        # [1-9 , user habit]
        # user_feature.setdefault(user, {})
        entry = [mapping[user]] # convert to id
        entry.extend(user_habit[user])
        # user_feature[user].setdefault("habit", user_habit[user])
        event = ["at", "acc", "dec", "os"]
        feature = {}
        for e in event:
            feature.setdefault(e, [0] * 3)
        if user in user_event:
            for e in user_event[user]:
                for i, _ in enumerate(user_event[user][e]):
                    feature[e][i] = _
        for e in event:
            entry.extend(feature[e])

        violation = [0, 0]
        if user in user_history:
            red = user_history[user].get("red", 0)
            collision = user_history[user].get("collision", 0)
            violation[0] = red
            violation[1] = collision
        entry.extend(violation)
        violation = [0, 0]
        if user in user_entry:
            red = user_entry[user].get("red", 0)
            collision = user_entry[user].get("collision", 0)
            violation[0] = red
            violation[1] = collision
        entry.extend(violation)
        user_feature.append(entry)

    header = "id,driving_time,driving_distance,max_speed,avg_speed,max_decelerate,max_accelerate,avg_decelerate,avg_accelerate,intersection"
    header = "{0},at_count,at_duration,at_distance,acc_count,acc_duration,acc_distance,dec_count,dec_duration,dec_distance,os_count,os_duration,os_distance,hr,hc,red,collision".format(header)

    # write feature
    csv_io.write_csv(os.path.join(options.output, "feature.csv"), user_feature, header=header)

if __name__ == '__main__':
    process(get_options())
